//
//  TL_ViewHelper.m
//  WXReader
//
//  Created by Andrew on 2019/7/9.
//  Copyright © 2019 Andrew. All rights reserved.
//

#import "TL_ViewHelper.h"

#import "AppDelegate.h"

@implementation TL_ViewHelper

#pragma mark -  上传图片处理

+ (UIWindow *)getKeyWindow {
    return KAppDelegate.window;
}

+ (void)setCornerWithLeftTopCorner:(CGFloat)leftTop
                    rightTopCorner:(CGFloat)rigtTop
                  bottomLeftCorner:(CGFloat)bottemLeft
                 bottomRightCorner:(CGFloat)bottemRight
                              view:(UIView *)view
                             frame:(CGRect)frame {
    
    CGFloat width = frame.size.width;
    CGFloat height = frame.size.height;
    
    UIBezierPath *maskPath = [UIBezierPath bezierPath];
    maskPath.lineWidth = 1.0;
    maskPath.lineCapStyle = kCGLineCapRound;
    maskPath.lineJoinStyle = kCGLineJoinRound;
    [maskPath moveToPoint:CGPointMake(bottemRight, height)]; //左下角
    [maskPath addLineToPoint:CGPointMake(width - bottemRight, height)];
    
    [maskPath addQuadCurveToPoint:CGPointMake(width, height- bottemRight) controlPoint:CGPointMake(width, height)]; //右下角的圆弧
    [maskPath addLineToPoint:CGPointMake(width, rigtTop)]; //右边直线
    
    [maskPath addQuadCurveToPoint:CGPointMake(width - rigtTop, 0) controlPoint:CGPointMake(width, 0)]; //右上角圆弧
    [maskPath addLineToPoint:CGPointMake(leftTop, 0)]; //顶部直线
    
    [maskPath addQuadCurveToPoint:CGPointMake(0, leftTop) controlPoint:CGPointMake(0, 0)]; //左上角圆弧
    [maskPath addLineToPoint:CGPointMake(0, height - bottemLeft)]; //左边直线
    [maskPath addQuadCurveToPoint:CGPointMake(bottemLeft, height) controlPoint:CGPointMake(0, height)]; //左下角圆弧

    CAShapeLayer *maskLayer = [CAShapeLayer layer];
    maskLayer.frame = frame;
    maskLayer.path = maskPath.CGPath;
    maskLayer.frame = frame;
    maskLayer.path = maskPath.CGPath;
    view.layer.mask = maskLayer;
}

+ (UIImage *)scaleImage:(UIImage *)image toScale:(float)scaleSize
{
    UIGraphicsBeginImageContext(CGSizeMake(SCREEN_WIDTH, PUB_TABBAR_HEIGHT));
    [image drawInRect:CGRectMake(0, 0, SCREEN_WIDTH, PUB_TABBAR_HEIGHT)];
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return scaledImage;
}

+ (NSString *)getBase64StringWithImageData:(NSData *)imageData
{
    return [self image2DataURL:[self imageWithImage:[self fixOrientation:[UIImage imageWithData:imageData]]]];
}

+ (UIImage *)fixOrientation:(UIImage *)aImage
{
    if (aImage.imageOrientation == UIImageOrientationUp) return aImage;
    
    CGAffineTransform transform = CGAffineTransformIdentity;
    
    switch (aImage.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height);
            transform = CGAffineTransformRotate(transform, M_PI);
            break;
            
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;
            
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, 0, aImage.size.height);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
        default:
            break;
    }
    
    switch (aImage.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.width, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
            
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            transform = CGAffineTransformTranslate(transform, aImage.size.height, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
        default:
            break;
    }
    CGContextRef ctx = CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height,
                                             CGImageGetBitsPerComponent(aImage.CGImage), 0,
                                             CGImageGetColorSpace(aImage.CGImage),
                                             CGImageGetBitmapInfo(aImage.CGImage));
    CGContextConcatCTM(ctx, transform);
    switch (aImage.imageOrientation) {
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage);
            break;
            
        default:
            CGContextDrawImage(ctx, CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage);
            break;
    }
    
    CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
    UIImage *img = [UIImage imageWithCGImage:cgimg];
    CGContextRelease(ctx);
    CGImageRelease(cgimg);
    
    return img;
}

+ (UIImage *)createNonInterpolatedUIImageFormCIImage:(NSString *)urlString withSize:(CGFloat)size {
    CIImage *image = [self creatQRcodeWithUrlstring:urlString];
    
    CGRect extent = CGRectIntegral(image.extent);
    CGFloat scale = MIN(size/CGRectGetWidth(extent), size/CGRectGetHeight(extent));
    
    // 1.创建bitmap;
    size_t width = CGRectGetWidth(extent) * scale;
    size_t height = CGRectGetHeight(extent) * scale;
    CGColorSpaceRef cs = CGColorSpaceCreateDeviceGray();
    CGContextRef bitmapRef = CGBitmapContextCreate(nil, width, height, 8, 0, cs, (CGBitmapInfo)kCGImageAlphaNone);
    CGColorSpaceRelease(cs);
    CIContext *context = [CIContext contextWithOptions:nil];
    CGImageRef bitmapImage = [context createCGImage:image fromRect:extent];
    CGContextSetInterpolationQuality(bitmapRef, kCGInterpolationNone);
    CGContextScaleCTM(bitmapRef, scale, scale);
    CGContextDrawImage(bitmapRef, extent, bitmapImage);
    
    // 2.保存bitmap到图片
    CGImageRef scaledImage = CGBitmapContextCreateImage(bitmapRef);
    CGContextRelease(bitmapRef);
    CGImageRelease(bitmapImage);
    UIImage *t_image = [UIImage imageWithCGImage:scaledImage];
    CGImageRelease(scaledImage);
    return t_image;
}

+ (CIImage *)creatQRcodeWithUrlstring:(NSString *)urlString {
    // 1.实例化二维码滤镜
    CIFilter *filter = [CIFilter filterWithName:@"CIQRCodeGenerator"];
    // 2.恢复滤镜的默认属性 (因为滤镜有可能保存上一次的属性)
    [filter setDefaults];
    // 3.将字符串转换成NSdata
    NSData *data  = [urlString dataUsingEncoding:NSUTF8StringEncoding];
    // 4.通过KVO设置滤镜, 传入data, 将来滤镜就知道要通过传入的数据生成二维码
    [filter setValue:data forKey:@"inputMessage"];
    // 5.生成二维码
    CIImage *outputImage = [filter outputImage];
    return outputImage;
}

+ (UIImage *)imageFromView:(UIView *)view
{
    if (CGRectIsEmpty(view.frame)) return nil;
    CGSize size = view.bounds.size;
    
    UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale);

    [view.layer renderInContext:UIGraphicsGetCurrentContext()];
    
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return image;
}

+ (UIImage *)imageWithImage:(UIImage *)image
{
    // 检查图像尺寸是否有效
    if (image.size.width <= 0 || image.size.height <= 0) {
        return image; // 返回原图，避免崩溃
    }
    
    UIGraphicsBeginImageContext(CGSizeMake(image.size.width, image.size.height));
    [image drawInRect:CGRectMake(0,0,image.size.width,image.size.height)];
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    return newImage;
}

+ (NSString *)image2DataURL: (UIImage *) image
{
    NSData *imageData = nil;
    NSString *mimeType = nil;
    
    imageData = UIImageJPEGRepresentation(image, 0.7f);
    mimeType = @"image/jpeg";
    
    return [NSString stringWithFormat:@"data:%@;base64,%@", mimeType,
            [imageData base64EncodedStringWithOptions: 0]];
    
}

+ (NSString *)getIconImageName {
    NSDictionary *infoPlist = [[NSBundle mainBundle] infoDictionary];
    NSString *icon = [[infoPlist valueForKeyPath:@"CFBundleIcons.CFBundlePrimaryIcon.CFBundleIconFiles"]lastObject];
    return icon;
}

+ (NSMutableAttributedString *)getSubContentWithOriginalContent:(NSMutableAttributedString *)originalContent labelWidth:(CGFloat)labelWidth labelMaxLine:(NSInteger)labelMaxLine
{
    if (originalContent.length == 0 || labelWidth == 0 || labelMaxLine == 0) {
        return nil;
    }
    
    // 计算总字符长度
    CGFloat totalStringLength = 0;
    
    for (int i = 0; i < [originalContent length]; i ++) {
        
        // 找出每个字符
        NSAttributedString *characterString = [originalContent attributedSubstringFromRange:NSMakeRange(i, 1)];
        
        // 处理换行符
        if ([characterString.string isEqualToString:@"\n"]) {
            
            // 换行符再当前行的位置(类似于取余)
            CGFloat currentDistanceToTop = totalStringLength - (int)(totalStringLength / labelWidth) * labelWidth;
            
            // 换行符到末尾的距离
            CGFloat distanceToEnd = labelWidth - currentDistanceToTop;
            
            totalStringLength = totalStringLength + distanceToEnd;
            
        } else {
            // 计算字符宽度
            CGFloat characterWidth = [characterString boundingRectWithSize:CGSizeMake(labelWidth, 0.0) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine context:nil].size.width;
            
            totalStringLength = totalStringLength + characterWidth;
        }
    }
    
    // 计算总字符有几行
    NSInteger characterTotalLine = (int)(totalStringLength / labelWidth);
    
    // 计算总字符最后一行宽度
    CGFloat endLineWidth = totalStringLength / labelWidth - characterTotalLine;
    
    // 是否需要截取
    BOOL needSeparated = NO;
    
    // 最后一行宽度大于限宽一半
    if (endLineWidth > 0.5) {
        needSeparated = YES;
    }
    
    // 总字符行数大于限制行数
    if (characterTotalLine > labelMaxLine) {
        needSeparated = YES;
        characterTotalLine = labelMaxLine;
    }
    
    // 进行截取
    if (needSeparated) {
        
        CGFloat finalCharacterLength = 0;
        for (int i = 0; i < [originalContent length]; i ++) {
            NSAttributedString *characterString = [originalContent attributedSubstringFromRange:NSMakeRange(i, 1)];
            
            if ([characterString.string isEqualToString:@"\n"]) {
                
                // 换行符再当前行的位置(类似于取余)
                CGFloat currentDistanceToTop = finalCharacterLength - (int)(finalCharacterLength / labelWidth) * labelWidth;
                
                // 换行符到末尾的距离
                CGFloat distanceToEnd = labelWidth - currentDistanceToTop;
                
                finalCharacterLength = finalCharacterLength + distanceToEnd;
                
            } else {
                // 计算字符宽度
                CGFloat characterWidth = [characterString boundingRectWithSize:CGSizeMake(labelWidth, 0.0) options:NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine context:nil].size.width;
                
                finalCharacterLength = finalCharacterLength + characterWidth -1;
            }
            
            //此处截取maxLength,根据需求设置
            if (finalCharacterLength >= labelWidth * (characterTotalLine + 0.5)) {
                NSMutableAttributedString *resultString = [[NSMutableAttributedString alloc] initWithAttributedString:[originalContent attributedSubstringFromRange:NSMakeRange(0, i)]];
                [resultString appendAttributedString:[[NSAttributedString alloc] initWithString:@"..."]];
                return resultString;
            }
        }
    }
    
    
    // 换行符再当前行的位置(类似于取余)
    CGFloat currentDistanceToTop = totalStringLength - (int)(totalStringLength / labelWidth) * labelWidth;
    
    // 如果当前行总字符长度不足一字符长度,则处理当前行的上一行内容
    if (currentDistanceToTop < 15) {
        
        if (characterTotalLine == 1) {
            [originalContent replaceCharactersInRange:NSMakeRange(originalContent.length / 2, originalContent.length - NSMakeRange(0, originalContent.length / 2).length) withString:@"..."];
        } else {
            return [self getSubContentWithOriginalContent:originalContent labelWidth:labelWidth labelMaxLine:labelMaxLine - 1];
        }
    }
    
    return originalContent;
}

+ (CGFloat)boundsWithFont:(UIFont *)font attributedText:(NSAttributedString *)attributedText needWidth:(CGFloat)needWidth lineSpacing:(CGFloat)lineSpacing
{
    NSMutableAttributedString *attributeString = [[NSMutableAttributedString alloc] initWithAttributedString:attributedText];
    
    NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];
    
    style.lineSpacing = lineSpacing;
    
    [attributeString addAttribute:NSParagraphStyleAttributeName value:style range:NSMakeRange(0, attributedText.length)];
    
    [attributeString addAttribute:NSFontAttributeName value:font range:NSMakeRange(0, attributedText.length)];
    
    NSStringDrawingOptions options = NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingTruncatesLastVisibleLine;
    
    CGRect rect = [attributeString boundingRectWithSize:CGSizeMake(needWidth, CGFLOAT_MAX) options:options context:nil];
    
    return rect.size.height;
    
}

+ (NSString *)imageExtensionWithFormatString:(NSString *)formatString
{
    if ([formatString isEqualToString:@"image/jpeg"]) {
        return @"jpeg";
    }
    
    if ([formatString isEqualToString:@"image/png"]) {
        return @"png";
    }
    
    if ([formatString isEqualToString:@"image/gif"]) {
        return @"gif";
    }
    
    if ([formatString isEqualToString:@"image/tiff"]) {
        return @"tiff";
    }
    
    if ([formatString isEqualToString:@"image/webp"]) {
        return @"webp";
    }
    
    return @"";
}

+ (NSString *)audioExtensionWithFormatString:(NSString *)formatString
{
    if ([formatString isEqualToString:@"audio/mpeg"] || [formatString isEqualToString:@"audio/x-mpeg-3"] || [formatString isEqualToString:@"audio/mpeg3"]) {
        return @"mp3";
    }

    if ([formatString isEqualToString:@"audio/wav"]) {
        return @"wav";
    }
    
    if ([formatString isEqualToString:@"audio/x-ma-wma"]) {
        return @"wma";
    }
    
    return @"";
}

#pragma mark - 自适应frame
// width
+ (CGFloat)getDynamicWidthWithLabel:(UILabel *)label
{
    return [self getDynamicWidthWithLabelFont:label.font labelHeight:label.bounds.size.height labelText:label.text maxWidth:MAXFLOAT];
}

+ (CGFloat)getDynamicWidthWithLabel:(UILabel *)label maxWidth:(CGFloat)maxWidth
{
    return [self getDynamicWidthWithLabelFont:label.font labelHeight:label.bounds.size.height labelText:label.text maxWidth:maxWidth];
}

+ (CGFloat)getDynamicWidthWithLabelFont:(UIFont *)labelFont labelHeight:(CGFloat)labelHeight labelText:(NSString *)labelText
{
    return [self getDynamicWidthWithLabelFont:labelFont labelHeight:labelHeight labelText:labelText maxWidth:MAXFLOAT];
}

+ (CGFloat)getDynamicWidthWithLabelFont:(UIFont *)labelFont labelHeight:(CGFloat)labelHeight labelText:(NSString *)labelText maxWidth:(CGFloat)maxWidth
{
    CGSize retSize = [self getDynamicSizeWithLabelFont:labelFont labelText:labelText rectWidth:maxWidth rectHeight:labelHeight];
    
    if (retSize.width + kMargin > maxWidth) {
        return maxWidth;
    }
    return retSize.width + 5;
}

+ (CGFloat)getContentWidthWithContent:(NSString *)content withFont:(UIFont *)font {
    NSDictionary *attribute = @{NSFontAttributeName:font};

    CGSize retSize = [content boundingRectWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX) options: NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:attribute context:nil].size;
    return retSize.width+1;
}

// height
+ (CGFloat)getDynamicHeightWithLabel:(UILabel *)label
{
    return [self getDynamicHeightWithLabelFont:label.font labelWidth:label.bounds.size.width labelText:label.text maxHeight:MAXFLOAT];
}

+ (CGFloat)getDynamicHeightWithLabel:(UILabel *)label maxHeight:(CGFloat)maxHeight
{
    return [self getDynamicHeightWithLabelFont:label.font labelWidth:label.bounds.size.width labelText:label.text maxHeight:maxHeight];
}

+ (CGFloat)getDynamicHeightWithLabelFont:(UIFont *)labelFont labelWidth:(CGFloat)labelWidth labelText:(NSString *)labelText
{
    return [self getDynamicHeightWithLabelFont:labelFont labelWidth:labelWidth labelText:labelText maxHeight:MAXFLOAT];
}

+ (CGFloat)getDynamicHeightWithLabelFont:(UIFont *)labelFont labelWidth:(CGFloat)labelWidth labelText:(NSString *)labelText maxHeight:(CGFloat)maxHeight
{
    CGSize retSize = [self getDynamicSizeWithLabelFont:labelFont labelText:labelText rectWidth:labelWidth rectHeight:maxHeight];
    
    if (retSize.height + kMargin > maxHeight) {
        return maxHeight;
    }
    return retSize.height + kMargin;
}

+ (CGSize)getDynamicSizeWithLabelFont:(UIFont *)labelFont labelText:(NSString *)labelText rectWidth:(CGFloat)rectWidth rectHeight:(CGFloat)rectHeight
{
    NSDictionary *attribute = @{NSFontAttributeName:labelFont};
    
    CGSize retSize = [labelText boundingRectWithSize:CGSizeMake(rectWidth, rectHeight)
                                             options:
                      NSStringDrawingTruncatesLastVisibleLine |
                      NSStringDrawingUsesLineFragmentOrigin |
                      NSStringDrawingUsesFontLeading
                                          attributes:attribute
                                             context:nil].size;
    return retSize;
}

#pragma mark - window
+ (UIViewController *)getWindowRootController
{
    UIViewController *rootController = kMainWindow.rootViewController;
    while (rootController.presentedViewController) {
      rootController = rootController.presentedViewController;
    }
    return rootController;
}

+ (UIViewController *)getCurrentViewController
{
    UIViewController * __block result = nil;
    DISPATCH_MAIN_THREAD(^{
        // 获取默认的window
        UIWindow * window = [[UIApplication sharedApplication] keyWindow];
        // app默认windowLevel是UIWindowLevelNormal，如果不是，找到它。
        if (window.windowLevel != UIWindowLevelNormal) {
            NSArray *windows = [[UIApplication sharedApplication] windows];
            for(UIWindow * tmpWin in windows) {
                if (tmpWin.windowLevel == UIWindowLevelNormal) {
                    window = tmpWin;
                    break;
                }
            }
        }
        
        // 获取window的rootViewController
        result = window.rootViewController;
        while (result.presentedViewController) {
            result = result.presentedViewController;
        }
        if ([result isKindOfClass:[UITabBarController class]]) {
            result = [(UITabBarController *)result selectedViewController];
        }
        if ([result isKindOfClass:[UINavigationController class]]) {
            result = [(UINavigationController *)result visibleViewController];
        }
    });
    return result;
}

+ (UINavigationController *)getCurrentNavigationController {
    UIWindow *window = [UIApplication sharedApplication].windows.firstObject;
    id rootViewController = window.rootViewController;
    if ([rootViewController isKindOfClass:UINavigationController.class]) {
        return (UINavigationController *)rootViewController;
    } else if ([rootViewController isKindOfClass:UITabBarController.class]) {
        UITabBarController *tabBarController = rootViewController;
        if (![tabBarController.selectedViewController isKindOfClass:UINavigationController.class]) return nil;
        return tabBarController.selectedViewController;
    }
    return nil;
}

+ (void)setStateBarLightStyle
{
    [UIApplication sharedApplication].statusBarHidden = NO;
    [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;
}

+ (void)setStateBarDefaultStyle
{
//    if (LLDarkManager.isDarkMode) {
//        [self setStateBarLightStyle];
//    } else {
        [UIApplication sharedApplication].statusBarHidden = NO;
        if (@available(iOS 13.0, *)) {
            [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDarkContent;
        } else {
            [UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleDefault;
        }
//    }
}

#pragma mark - 特殊字体

// 删除线
+ (NSMutableAttributedString *)addPartionLineWithString:(NSString *)string range:(NSRange)range
{
    NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithString:string];
    [attributedStr addAttribute:NSStrikethroughStyleAttributeName value:@(NSUnderlineStyleSingle) range:range];
    return attributedStr;
}
// 下划线
+ (NSMutableAttributedString *)addUnderLineWithString:(NSString *)string range:(NSRange)range
{
    NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithString:string];
    [attributedStr addAttribute:NSUnderlineStyleAttributeName value:@(NSUnderlineStyleSingle) range:range];
    return attributedStr;
}

// 字体变大
+ (NSMutableAttributedString *)resetFontWithFont:(UIFont *)font string:(NSString *)string range:(NSRange)range
{
    NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithString:string];
    [attributedStr addAttribute:NSFontAttributeName value:font range:range];
    return attributedStr;
}

// 字体变色
+ (NSMutableAttributedString *)resetColorWithColor:(UIColor *)color string:(NSString *)string range:(NSRange)range
{
    NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithString:string];
    [attributedStr addAttribute:NSForegroundColorAttributeName value:color range:range];
    return attributedStr;
}

// 字体加粗
+ (NSMutableAttributedString *)resetBoldFontWithString:(NSString *)string range:(NSRange)range
{
    NSMutableAttributedString *attributedStr = [[NSMutableAttributedString alloc] initWithString:string];
    [attributedStr addAttribute:NSExpansionAttributeName value:[NSNumber numberWithInt:1] range:range];
    return attributedStr;
}


+ (CGSize)calcTextSize:(CGSize)fitSize
                  text:(id)text
         numberOfLines:(NSInteger)numberOfLines
                  font:(nullable UIFont *)font
         textAlignment:(NSTextAlignment)textAlignment
         lineBreakMode:(NSLineBreakMode)lineBreakMode
    minimumScaleFactor:(CGFloat)minimumScaleFactor
          shadowOffset:(CGSize)shadowOffset {
    if (!text || [text length] <= 0) {
        return CGSizeZero;
    }
    
    NSAttributedString *calcAttributedString = nil;
    
    CGFloat systemVersion = [[UIDevice currentDevice].systemVersion floatValue];
    
    NSMutableParagraphStyle *paragraphStyle = [[NSMutableParagraphStyle alloc] init];
    paragraphStyle.alignment = textAlignment;
    paragraphStyle.lineBreakMode = lineBreakMode;
    
    // 系统大于11才设置行断字策略
    if (systemVersion >= 11.0) {
        @try {
            [paragraphStyle setValue:@(1) forKey:@"lineBreakStrategy"];
        } @catch (NSException *exception) {}
    }
    
    if ([text isKindOfClass:NSString.class]) {
        calcAttributedString = [[NSAttributedString alloc] initWithString:(NSString *)text attributes:@{NSFontAttributeName : font, NSParagraphStyleAttributeName : paragraphStyle}];
    } else {
        NSAttributedString *originAttributeString = (NSAttributedString *)text;
        // 对于属性字符串总是加上默认的字体和段落信息
        NSMutableAttributedString *mutableCalcAttributedString = [originAttributeString mutableCopy];
        [mutableCalcAttributedString setAttribute:NSParagraphStyleAttributeName value:paragraphStyle];
        
        // 这里再次取段落信息，因为有可能属性字符串中就已经包含了段落信息
        if (systemVersion >= 11.0) {
            NSParagraphStyle *alternativeParagraphStyle = [mutableCalcAttributedString attribute:NSParagraphStyleAttributeName atIndex:0 effectiveRange:NULL];
            if (alternativeParagraphStyle != nil) {
                paragraphStyle = (NSMutableParagraphStyle *)alternativeParagraphStyle;
            }
        }
        
        calcAttributedString = mutableCalcAttributedString;
    }
    
    // 调整fitSize的值，这里的宽度调整为只要宽度小于等于0或者显示一行都不限制宽度，而高度则总是改为不限制
    fitSize.height = FLT_MAX;
    if (fitSize.width <= 0 || numberOfLines == 1) {
        fitSize.width = FLT_MAX;
    }
    
    // 构造出一个NSStringDrawContext
    NSStringDrawingContext *context = [[NSStringDrawingContext alloc] init];
    context.minimumScaleFactor = minimumScaleFactor;
    @try {
        // 因为下面几个属性都是未公开的属性，所以使用KVC
        [context setValue:@(numberOfLines) forKey:@"maximumNumberOfLines"];
        if (numberOfLines != 1) {
            [context setValue:@(YES) forKey:@"wrapsForTruncationMode"];
        }
        [context setValue:@(YES) forKey:@"wantsNumberOfLineFragments"];
    } @catch (NSException *exception) {}
    
    // 计算属性字符串的bounds值
    CGRect rect = [calcAttributedString boundingRectWithSize:fitSize options:NSStringDrawingUsesLineFragmentOrigin context:context];
    
    // 需要对段落的首行缩进进行特殊处理
    // 如果只有一行则直接添加首行缩进的值，否则进行特殊处理
    CGFloat firstLineHeadIndent = paragraphStyle.firstLineHeadIndent;
    if (firstLineHeadIndent != 0.0 && systemVersion >= 11.0) {
        // 得到绘制出来的行数
        NSInteger numberOfDrawingLines = [[context valueForKey:@"numberOfLineFragments"] integerValue];
        if (numberOfDrawingLines == 1) {
            rect.size.width += firstLineHeadIndent;
        } else {
            // 取内容的行数
            NSString *string = calcAttributedString.string;
            NSCharacterSet *charset = [NSCharacterSet newlineCharacterSet];
            NSArray *lines = [string componentsSeparatedByCharactersInSet:charset];// 得到文本内容的行数
            NSString *lastLine = lines.lastObject;
            NSInteger numberOfContentLines = lines.count - (NSInteger)(lastLine.length == 0); // 有效的内容行数要减去最后一行为空行的情况。
            if (numberOfLines == 0) {
                numberOfLines = NSIntegerMax;
            }
            if (numberOfLines > numberOfContentLines) {
                numberOfLines = numberOfContentLines;
            }
            
            // 只有绘制的行数和指定的行数相等时才添加上首行缩进，这段代码根据反汇编来实现，但是不理解为什么相等才设置？
            if (numberOfDrawingLines == numberOfLines) {
                rect.size.width += firstLineHeadIndent;
            }
        }
    }
    
    // 取fitSize和rect中的最小宽度值
    if (rect.size.width > fitSize.width) {
        rect.size.width = fitSize.width;
    }
    
    // 加上阴影的偏移
    rect.size.width += fabs(shadowOffset.width);
    rect.size.height += fabs(shadowOffset.height);
    
    // 转化为可以有效显示的逻辑点，这里将原始逻辑点乘以缩放比例得到物理像素点，然后再取整，然后再除以缩放比例得到可以有效显示的逻辑点。
    CGFloat scale = [UIScreen mainScreen].scale;
    rect.size.width = ceil(rect.size.width * scale) / scale;
    rect.size.height = ceil(rect.size.height * scale) / scale;
    
    return rect.size;
}

@end
